/**
 * 
 */
package org.vsg.stock.basic.service.business;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vsg.stock.basic.domain.BalanceLine;
import org.vsg.stock.basic.domain.BalanceLineFactory;
import org.vsg.stock.basic.domain.BalanceLineKeyPoint;
import org.vsg.stock.basic.service.StockBusinessHelper;
import org.vsg.stock.core.domain.StockDailyKLine;
import org.vsg.stock.core.indicator.KLineStockIndicatorModel;
import org.vsg.stock.core.indicator.ZigIndicator;
import org.vsg.stock.core.indicator.kline.ZigIndicatorResultItem;

/**
 * @author Bill Vison
 *
 */
public class CrestBalanceLineFinderBO extends
	OrgDataStockBalanceLineFinderBO {

	private static final Logger logger = LoggerFactory.getLogger(CrestBalanceLineFinderBO.class);

	private BalanceLineFactory factory = BalanceLineFactory.getInstance();
	
	private static final String FINDER_CODE = "crest_balance_line";
	
	@Override
	public String getFinderCode() {
		// TODO Auto-generated method stub
		return FINDER_CODE;
	}	
	
	@Override
	protected List<BalanceLine> scanLines(List<StockDailyKLine>  stkKlineList) {

		// --- scan and mark point in to list and map ---
		KLineStockIndicatorModel klineStkIndiModel = 
			new KLineStockIndicatorModel(stkKlineList ,KLineStockIndicatorModel.KLinePosition.HIGH);

		ZigIndicator zigInd = new ZigIndicator();
		// 过细,将无法分出波,过大找的波较少,对于价来说, 3-3.3为合适
		zigInd.setThreshold( (double)3.2 );
		zigInd.setIndicatorModel( klineStkIndiModel );
		
		Map<String, java.io.Serializable > resultMap  = zigInd.calculate();		
		
		// --- use one point value check ---
		List<ZigIndicatorResultItem> crests = (List<ZigIndicatorResultItem>) resultMap.get( ZigIndicator.ALL_CREST );
		
		if ( logger.isInfoEnabled() ) {
			for (ZigIndicatorResultItem item : crests) {
				StockDailyKLine  refOuterKLine = (StockDailyKLine)item.getAssoRef();
	
			}
		}

		List<BalanceLine> allLine = checkAndMergePointToLine(crests);

		if ( logger.isInfoEnabled() ) {
			for (BalanceLine line : allLine) {
				System.out.println( line );		
			}
		}
		
		
		return allLine;
	}
	
	private List<BalanceLine> checkAndMergePointToLine(List<ZigIndicatorResultItem> crests) {
		Set<Integer> usedIndex = new HashSet<Integer>();

		List<BalanceLine> allLines = new Vector<BalanceLine>();
		
		// ---- check to merge line point ----
		ZigIndicatorResultItem outerItem = null;
		ZigIndicatorResultItem innerItem = null;
		for (int i = 0 ; i < crests.size() ; i++) {
			
			if (usedIndex.contains(i)) {
				continue;
			}
			outerItem = crests.get(i);
			usedIndex.add(i);
			
			StockDailyKLine  refOuterKLine = (StockDailyKLine)outerItem.getAssoRef();
			double outerStandardPrice = refOuterKLine.getHigh();
			
			double sum = outerStandardPrice;
			int count = 1;

			BalanceLine line = factory.createLine(refOuterKLine.getId().getStockCode(), BalanceLine.FORM_H);

			
			BalanceLineKeyPoint basicKeyPoint = new BalanceLineKeyPoint();
			basicKeyPoint.setPriceType( BalanceLineKeyPoint.HIGH );
			basicKeyPoint.setPrice( outerStandardPrice );
			basicKeyPoint.setRefDate( refOuterKLine.getDate() );
			
			line.addKeyPoint(basicKeyPoint);
			
			StringBuffer logStr = null;
			if ( logger.isDebugEnabled() ) {
				logStr = new StringBuffer("P:");
				logStr.append("[").append(df.format( refOuterKLine.getDate() )).append("] : ");
			}
			
			for (int j = i+1 ; j < crests.size() ; j++) {

				if (usedIndex.contains(j)) {
					continue;
				}
				innerItem = crests.get(j);


				StockDailyKLine  refInnerKLine = (StockDailyKLine)innerItem.getAssoRef();
				double innerStandardPrice = refInnerKLine.getHigh();
				
				// --- handle different logic by price ---
				boolean canMerge = false;
				double diff = Math.abs( outerStandardPrice - innerStandardPrice ) / outerStandardPrice * 100;

				// --- stock with low price will be set the higher of the radio than high price
				canMerge = StockBusinessHelper.checkDiffScope(outerStandardPrice, diff);
				
				if ( canMerge ) {
					usedIndex.add(j);					
					if ( logger.isDebugEnabled() ) {
						logStr.append(df.format( refInnerKLine.getDate() )).append(" ");
					}

					sum += innerStandardPrice;
					count += 1;
					
					
					// --- grouping keypoint ----
					BalanceLineKeyPoint otherKeyPoint = new BalanceLineKeyPoint();
					otherKeyPoint.setPriceType( BalanceLineKeyPoint.HIGH );
					otherKeyPoint.setPrice( innerStandardPrice );
					otherKeyPoint.setRefDate( refInnerKLine.getDate() );
					line.addKeyPoint( otherKeyPoint );
					
				}
			}
			
			allLines.add(line);
			
		}
		
		
		
		return allLines;
	}
	
	

	
	
	
}
